﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;

namespace EncryptProject
{
    /// <summary>
    /// 加密算法
    /// </summary>
    public static class EncryptAlgorithmHelper
    {
        private const string KEY = "http://xjcyw-1234.wicp.net/"; // 默认密钥

        #region AES 数据加密

        /// <summary> 
        /// AES 加密数据
        /// </summary> 
        /// <param name="input">加密前的字符串</param> 
        /// <param name="extInfor">附加字符串</param>
        /// <returns>加密后的字符串</returns> 
        public static string Encrypt(string input, string extInfor = null)
        {
            // 盐值 
            string saltValue = string.Format("{0}【{1}】", KEY, extInfor);
            // 密码值 
            string pwdValue = string.Format("{0}【{1}】", extInfor, KEY);
            byte[] data = System.Text.UTF8Encoding.UTF8.GetBytes(input);
            byte[] salt = System.Text.UTF8Encoding.UTF8.GetBytes(saltValue);
            // AesManaged - 高级加密标准(AES) 对称算法的管理类 
            System.Security.Cryptography.AesManaged aes = new System.Security.Cryptography.AesManaged();
            // Rfc2898DeriveBytes - 通过使用基于 HMACSHA1 的伪随机数生成器，实现基于密码的密钥派生功能 (PBKDF2 - 一种基于密码的密钥派生函数) 
            // 通过 密码 和 salt 派生密钥 
            System.Security.Cryptography.Rfc2898DeriveBytes rfc = new System.Security.Cryptography.Rfc2898DeriveBytes(pwdValue, salt);
            aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
            aes.KeySize = aes.LegalKeySizes[0].MaxSize;
            aes.Key = rfc.GetBytes(aes.KeySize / 8);
            aes.IV = rfc.GetBytes(aes.BlockSize / 8);
            // 用当前的 Key 属性和初始化向量 IV 创建对称加密器对象 
            System.Security.Cryptography.ICryptoTransform encryptTransform = aes.CreateEncryptor();
            // 加密后的输出流 
            System.IO.MemoryStream encryptStream = new System.IO.MemoryStream();
            // 将加密后的目标流（encryptStream）与加密转换（encryptTransform）相连接 
            System.Security.Cryptography.CryptoStream encryptor = new System.Security.Cryptography.CryptoStream
                (encryptStream, encryptTransform, System.Security.Cryptography.CryptoStreamMode.Write);
            // 将一个字节序列写入当前 CryptoStream （完成加密的过程） 
            encryptor.Write(data, 0, data.Length);
            encryptor.Close();
            // 将加密后所得到的流转换成字节数组，再用Base64编码将其转换为字符串 
            string encryptedString = Convert.ToBase64String(encryptStream.ToArray());
            return encryptedString;
        }

        /// <summary> 
        /// AES 解密数据 
        /// </summary> 
        /// <param name="input">加密后的字符串</param> 
        /// <param name="extInfor">附加字符串</param>
        /// <returns>加密前的字符串</returns> 
        public static string Decrypt(string input, string extInfor = null)
        {
            // 盐值（与加密时设置的值一致） 
            string saltValue = string.Format("{0}【{1}】", KEY, extInfor);
            // 密码值（与加密时设置的值一致） 
            string pwdValue = string.Format("{0}【{1}】", extInfor, KEY);
            byte[] encryptBytes = Convert.FromBase64String(input);
            byte[] salt = Encoding.UTF8.GetBytes(saltValue);
            System.Security.Cryptography.AesManaged aes = new System.Security.Cryptography.AesManaged();
            System.Security.Cryptography.Rfc2898DeriveBytes rfc = new System.Security.Cryptography.Rfc2898DeriveBytes(pwdValue, salt);
            aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
            aes.KeySize = aes.LegalKeySizes[0].MaxSize;
            aes.Key = rfc.GetBytes(aes.KeySize / 8);
            aes.IV = rfc.GetBytes(aes.BlockSize / 8);
            // 用当前的 Key 属性和初始化向量 IV 创建对称解密器对象 
            System.Security.Cryptography.ICryptoTransform decryptTransform = aes.CreateDecryptor();
            // 解密后的输出流 
            System.IO.MemoryStream decryptStream = new System.IO.MemoryStream();
            // 将解密后的目标流（decryptStream）与解密转换（decryptTransform）相连接 
            System.Security.Cryptography.CryptoStream decryptor = new System.Security.Cryptography.CryptoStream(
                decryptStream, decryptTransform, System.Security.Cryptography.CryptoStreamMode.Write);
            // 将一个字节序列写入当前 CryptoStream （完成解密的过程） 
            decryptor.Write(encryptBytes, 0, encryptBytes.Length);
            decryptor.Close();
            // 将解密后所得到的流转换为字符串 
            byte[] decryptBytes = decryptStream.ToArray();
            string decryptedString = UTF8Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
            return decryptedString;
        }

        #endregion


        #region DES 数据加密

        /// <summary>
        /// DES 加密方法 
        /// </summary>
        /// <param name="pToEncrypt">加密字符串</param>
        /// <param name="keyStr">密钥可以为空，默认密钥为＂http://xjcyw-1234.wicp.net/＂</param>
        /// <returns></returns>
        public static string Encrypt2(string pToEncrypt, string keyStr = null)
        {
            MemoryStream ms = null;
            CryptoStream cs = null;
            StringBuilder ret = null;
            byte[] sKey;
            byte[] sIV;

            try
            {
                DESCryptoServiceProvider des = new DESCryptoServiceProvider();
                if (keyStr == null || keyStr == "")
                    keyStr = KEY;
                //把字符串放到byte数组中   
                //原来使用的UTF8编码，我改成Unicode编码了，不行   
                byte[] inputByteArray = Encoding.Default.GetBytes(pToEncrypt);
                byte[] keyByteArray = Encoding.Default.GetBytes(keyStr);
                SHA1 ha = new SHA1Managed();
                byte[] hb = ha.ComputeHash(keyByteArray);

                sKey = new byte[8];
                sIV = new byte[8];

                for (int i = 0; i < 8; i++)
                    sKey[i] = hb[i];
                for (int i = 8; i < 16; i++)
                    sIV[i - 8] = hb[i];
                des.Key = sKey;
                des.IV = sIV;

                ms = new MemoryStream();
                cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
                cs.Write(inputByteArray, 0, inputByteArray.Length);
                cs.FlushFinalBlock();
                ret = new StringBuilder();
                foreach (byte b in ms.ToArray())
                {
                    ret.AppendFormat("{0:X2}", b);
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                if (null != cs) cs.Close();
                if (null != ms) ms.Close();
            }
            return ret.ToString();
        }

        /// <summary>
        /// DES 解密方法  
        /// </summary>
        /// <param name="pToDecrypt">解密字符串</param>
        /// <param name="keyStr">密钥可以为空，默认密钥为＂http://xjcyw-1234.wicp.net/＂</param>
        /// <returns></returns>
        public static string Decrypt2(string pToDecrypt, string keyStr = null)
        {
            MemoryStream ms = null;
            CryptoStream cs = null;
            byte[] sKey;
            byte[] sIV;
            sKey = new byte[8];
            sIV = new byte[8];
            string values = "";

            DESCryptoServiceProvider des = new DESCryptoServiceProvider();

            if (keyStr == null || keyStr == "")
                keyStr = KEY;

            byte[] inputByteArray = new byte[pToDecrypt.Length / 2];
            for (int x = 0; x < pToDecrypt.Length / 2; x++)
            {
                int i = (Convert.ToInt32(pToDecrypt.Substring(x * 2, 2), 16));
                inputByteArray[x] = (byte)i;
            }
            try
            {
                byte[] keyByteArray = Encoding.Default.GetBytes(keyStr);
                SHA1 ha = new SHA1Managed();
                byte[] hb = ha.ComputeHash(keyByteArray);

                for (int i = 0; i < 8; i++)
                    sKey[i] = hb[i];
                for (int i = 8; i < 16; i++)
                    sIV[i - 8] = hb[i];
                des.Key = sKey;
                des.IV = sIV;
                ms = new MemoryStream();
                cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
                cs.Write(inputByteArray, 0, inputByteArray.Length);
                cs.FlushFinalBlock();
                //建立StringBuild对象，CreateDecrypt使用的是流对象，必须把解密后的文本变成流对象   
                values = System.Text.Encoding.Default.GetString(ms.ToArray());
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                cs.Close();
                ms.Close();
            }
            return values;
        }

        #endregion


        #region MD5 数据加密

        /// <summary>
        /// 取得输入字符串的 MD5 哈希值
        /// </summary>
        /// <param name="argInput">输入字符串</param>
        /// <returns>MD5 哈希值</returns>
        public static string MD5Hash(string argInput)
        {
            // Create a new instance of the MD5CryptoServiceProvider object.
            MD5 md5Hasher = MD5.Create();

            // Convert the input string to a byte array and compute the hash.
            byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(argInput));

            // Create a new Stringbuilder to collect the bytes
            // and create a string.
            StringBuilder sBuilder = new StringBuilder();

            // Loop through each byte of the hashed data 
            // and format each one as a hexadecimal string.
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }

            // Return the hexadecimal string.
            return sBuilder.ToString();
        }

        /// <summary>
        /// 验证 MD5 哈希值
        /// </summary>
        /// <param name="argInput">输入字符串</param>
        /// <param name="argHash">哈希值</param>
        /// <returns>相同返回TRUE,不同返回FALSE</returns>
        public static bool VerifyMD5Hash(string argInput, string argHash)
        {
            // Hash the input.
            string hashOfInput = MD5Hash(argInput);

            // Create a StringComparer an comare the hashes.
            StringComparer comparer = StringComparer.OrdinalIgnoreCase;

            if (0 == comparer.Compare(hashOfInput, argHash))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        #endregion
    }
}